﻿#include <iostream>
#include <fstream>
#include <lzma.h>

const size_t BUFFER_SIZE = 1024 * 1024; // 1MB buffer

void compressFile(const char* inputFileName, const char* outputFileName) {
    std::ifstream inputFile(inputFileName, std::ios::binary);
    std::ofstream outputFile(outputFileName, std::ios::binary);

    if (!inputFile.is_open() || !outputFile.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
        return;
    }

    char inBuffer[BUFFER_SIZE];
    char outBuffer[BUFFER_SIZE];
    lzma_stream stream = LZMA_STREAM_INIT;
    lzma_ret ret = lzma_easy_encoder(&stream, 6, LZMA_CHECK_CRC64);

    if (ret != LZMA_OK) {
        std::cerr << "初始化编码器失败" << std::endl;
        return;
    }

    while (true) {
        inputFile.read(inBuffer, BUFFER_SIZE);
        stream.next_in = reinterpret_cast<uint8_t*>(inBuffer);
        stream.avail_in = static_cast<size_t>(inputFile.gcount());

        do {
            stream.next_out = reinterpret_cast<uint8_t*>(outBuffer);
            stream.avail_out = BUFFER_SIZE;
            ret = lzma_code(&stream, LZMA_RUN);

            if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
                std::cerr << "压缩错误" << std::endl;
                lzma_end(&stream);
                return;
            }

            outputFile.write(outBuffer, BUFFER_SIZE - stream.avail_out);
        } while (stream.avail_out == 0);

        if (inputFile.eof()) break;
    }

    do {
        stream.next_out = reinterpret_cast<uint8_t*>(outBuffer);
        stream.avail_out = BUFFER_SIZE;
        ret = lzma_code(&stream, LZMA_FINISH);

        if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
            std::cerr << "压缩错误" << std::endl;
            lzma_end(&stream);
            return;
        }

        outputFile.write(outBuffer, BUFFER_SIZE - stream.avail_out);
    } while (stream.avail_out == 0);

    lzma_end(&stream);
    inputFile.close();
    outputFile.close();
}

void decompressFile(const char* inputFileName, const char* outputFileName) {
    std::ifstream inputFile(inputFileName, std::ios::binary);
    std::ofstream outputFile(outputFileName, std::ios::binary);

    if (!inputFile.is_open() || !outputFile.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
        return;
    }

    char inBuffer[BUFFER_SIZE];
    char outBuffer[BUFFER_SIZE];
    lzma_stream stream = LZMA_STREAM_INIT;
    lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, 0);

    if (ret != LZMA_OK) {
        std::cerr << "初始化解码器失败" << std::endl;
        return;
    }

    while (true) {
        inputFile.read(inBuffer, BUFFER_SIZE);
        stream.next_in = reinterpret_cast<uint8_t*>(inBuffer);
        stream.avail_in = static_cast<size_t>(inputFile.gcount());

        do {
            stream.next_out = reinterpret_cast<uint8_t*>(outBuffer);
            stream.avail_out = BUFFER_SIZE;
            ret = lzma_code(&stream, LZMA_RUN);

            if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
                std::cerr << "解压缩错误" << std::endl;
                lzma_end(&stream);
                return;
            }

            outputFile.write(outBuffer, BUFFER_SIZE - stream.avail_out);
        } while (stream.avail_out == 0);

        if (inputFile.eof()) break;
    }

    do {
        stream.next_out = reinterpret_cast<uint8_t*>(outBuffer);
        stream.avail_out = BUFFER_SIZE;
        ret = lzma_code(&stream, LZMA_FINISH);

        if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
            std::cerr << "解压缩错误" << std::endl;
            lzma_end(&stream);
            return;
        }

        outputFile.write(outBuffer, BUFFER_SIZE - stream.avail_out);
    } while (stream.avail_out == 0);

    lzma_end(&stream);
    inputFile.close();
    outputFile.close();
}

int main() {
    const char* inputFileName = "input.bin";
    const char* compressedFileName = "compressed.bin";
    const char* decompressedFileName = "decompressed.bin";

    compressFile(inputFileName, compressedFileName);
    decompressFile(compressedFileName, decompressedFileName);

    return 0;
}